import { useCreateCall, useSimpleMemo } from '@/components';
import { arrayUnique, isEqualStrictDeep, notNull } from '@/utils';
import { Select } from 'antd';
import * as PropTypes from 'prop-types';
import React, { createContext, memo, useMemo } from 'react';

export const defaultCol = {
  xs: 24,
  md: 12,
  xl: 8,
};

const toGetProps = (onItem, props) => {
  return (args, ...rest) => {
    let onItemProps = { ...props };
    if (typeof onItem === 'function') onItemProps = { ...onItemProps, ...onItem(...args) };
    rest.forEach((obj) => {
      if (typeof obj === 'function') onItemProps = { ...onItemProps, ...obj(...args) };
      if (typeof obj === 'object') onItemProps = { ...onItemProps, ...obj };
    });
    return onItemProps;
  };
};

export const FormContext = createContext({ form: null, onCol: null, onItem: null, onField: null });

FormProvider = memo(FormProvider, isEqualStrictDeep);

export function FormProvider(props) {
  let { useKeys, useProps, children, ...rest } = props;
  const createCall = useCreateCall();

  const context = useMemo(() => {
    const allUseKeys = arrayUnique(['form', 'labelSpan', 'wrapperSpan'].concat(useKeys ?? []));
    const allUseProps = arrayUnique(['item', 'field'].concat(useProps ?? []));
    const keysObject = allUseKeys.reduce((ret, k) => ({ ...ret, [k]: rest[k] ?? null }), {});
    const propObject = allUseProps.reduce((ret, k) => {
      const keyOn = `on${k.replace(/^[a-z]/, (v) => v.toUpperCase())}`;
      const keyProps = `${k}Props`;

      return {
        ...ret,
        [keyOn]: createCall(toGetProps(rest[keyOn], rest[keyProps])),
      };
    }, {});

    return {
      ...keysObject,
      ...propObject,
    };
  }, [useSimpleMemo([rest, useKeys, useProps])]);

  const ctx = useSimpleMemo(context);

  return <FormContext.Provider value={ctx}>{children}</FormContext.Provider>;
}

FormProvider.propTypes = {
  useKeys: PropTypes.arrayOf(PropTypes.string),
  useProps: PropTypes.arrayOf(PropTypes.string),
  children: PropTypes.node,
};

export function concatName(a, b) {
  let arr;

  if (Array.isArray(a)) {
    arr = [...a];
  } else {
    arr = [a];
  }

  if (Array.isArray(b)) {
    arr = [...arr, ...b];
  } else {
    arr = [...arr, b];
  }

  arr = arr.reduce((ret, item) => {
    if (item === '../' && ret.length > 0) {
      ret.pop();
      return ret;
    }
    return [...ret, item];
  }, []);

  return arr.filter((v) => v != null);
}

function mapSubField(n, l) {
  return ([nn, ...pp]) => mapField([nn, l, ...pp]);
}

export function mapField([n, l, t, { required, rules, fields, ...p } = {}]) {
  const scope = this?.scope ?? [];
  const name = concatName(scope, n);
  const mergeObj = this?.merge ?? {};

  return {
    ...mergeObj,
    name,
    label: l,
    type: t ?? 'text',
    ...(l && (['dict', 'select', 'text', 'input-number'].includes(t) || t == null)
      ? { placeholder: `${['dict', 'select'].includes(t) ? '请选择' : '请输入'}${l}` }
      : null),
    ...(required ? { rules: [{ required: true, message: `请输入${l}` }, ...(rules ?? [])] } : { rules: rules ?? [] }),
    ...(Array.isArray(fields) && fields.length ? { fields: fields.map(mapSubField(name, l)) } : null),
    ...p,
  };
}

export const mapReadOnly = (fields) => {
  const mapItem = (vv) => {
    vv = { ...vv };
    if (['radio-group', 'checkbox-group', 'switch', 'radio', 'checkbox'].includes(vv.type)) {
      vv.disabled = true;
    } else {
      vv.readOnly = true;
    }
    if (vv.type === 'select' || (vv.type === 'dict' && (!vv.component || vv.component === Select))) {
      vv.open = false;
    }
    if (notNull(vv.mode)) {
      if (vv.mode === 'tags') {
        vv.onInputKeyDown = (e) => {
          e.preventDefault();
          e.stopPropagation();
        };
      }
      vv.removeIcon = null;
      vv.mode = 'multiple';
    }

    return vv;
  };
  return fields.map((v) => {
    if (v.fields) {
      return { ...v, fields: v.fields.map(mapItem) };
    }
    return mapItem(v);
  });
};
